package main.flex.component.main
{
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import main.flex.component.main.tooltip.FlexAnimatedCatTooltip;
	import main.flex.component.main.value.FlexAnimatedCatStateVO;
	import main.flex.conf.MainConf;
	import main.flex.utils.CursorHandler;
	import main.flex.widget.template.WiiavieHelpWidget;
	
	import mx.containers.Canvas;
	import mx.containers.VBox;
	import mx.controls.Alert;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	import mx.events.ToolTipEvent;
	import mx.managers.ToolTipManager;
	
	import org.servebox.commons.utils.ArrayUtils;
	
	public class FlexAnimatedCat extends AnimatedCat
	{
		
		////////////////////////////////////////////////////////////////////////////////
		// CONVENTION DE NOMMAGE POUR LES ETATS DU CHAT
		////////////////////////////////////////////////////////////////////////////////
		/* suffixes */
		public static const UNDERSCORE				: String 	= "_";
		public static const START					: String 	= "start";
		public static const END 					: String 	= "end";
		
		/* noms d'états */
		public static const IDLE_INITIAL			: String	= "idle";
		
		public static const IDLE_HEADSHAKE			: String	= "hochement";
		public static const IDLE_TAILSHAKE			: String	= "queue";
		public static const IDLE_PAWSHAKE			: String	= "patte";
		
		public static const ACTIVE_MEOW				: String	= "miaou";
		
		public static const IDLE_TO_INACTIVE		: String	= "endort";
		public static const INACTIVE_TO_IDLE		: String	= "reveil";
		
		public static const INACTIVE_DROWSE			: String	= "somnole";
		public static const INACTIVE_SLEEP			: String	= "dodo";
		public static const INACTIVE_YAWN			: String	= "sommeil";
		////////////////////////////////////////////////////////////////////////////////
		
		////////////////////////////////////////////////////////////////////////////////
		
		private static const ADJUST_X				: Number	= 120;
		private static const ADJUST_Y				: Number	= 100;
		
		////////////////////////////////////////////////////////////////////////////////
		// PROPRIETES INTERNES DE LA CLASSE
		////////////////////////////////////////////////////////////////////////////////
		private var labels							: Object;
		
		private var _statesRequested				: Array 	= new Array();
		
		private var _isActive 						: Boolean 	= true;
		private var _readyToPlay					: Boolean 	= true;
		
		private var _currentSection					: String;
		private var _currentHelpMessage				: String	= MainConf.LOGIN_HELP_MESSAGE;
		private var _hasEnteredSection				: Boolean;
		
		public var helpTextToDisplay				: String	= MainConf.LOGIN_HELP_MESSAGE;	
		////////////////////////////////////////////////////////////////////////////////
		
		////////////////////////////////////////////////////////////////////////////////
		// CONSTRUCTEUR
		////////////////////////////////////////////////////////////////////////////////
		
		public function FlexAnimatedCat()
		{
			super();
			
			addEventListener( ToolTipEvent.TOOL_TIP_CREATE, createCustomTooltip );
			addEventListener( ToolTipEvent.TOOL_TIP_SHOW, positionCustomTooltip );
			
			this.includeInLayout 		= false;
			
			addEventListener(FlexEvent.CREATION_COMPLETE, configureTooltipManager );
		}
		
		private function configureTooltipManager( e : FlexEvent ) : void
		{
			ToolTipManager.showDelay 	= 200;
			ToolTipManager.hideDelay 	= Infinity;
			ToolTipManager.showEffect 	= WiiavieHelpWidget( VBox( Canvas( owner ).owner ).owner ).toolTipShowEffect;
			
			//currentSection = MainConf.LOGIN_VIEW;
		}
		
		////////////////////////////////////////////////////////////////////////////////
		// METHODES DE GESTION INTERNE DE LA CLASSE
		////////////////////////////////////////////////////////////////////////////////
		
		override public function initialize ( ) : void
		{
			super.initialize();
			
			mapLabels();
			
			currentSection = MainConf.LOGIN_VIEW;
			
			addEventListener( Event.ENTER_FRAME, handleStateChange );
			addEventListener( MouseEvent.MOUSE_OVER, requestHelp );
			addEventListener( MouseEvent.CLICK, handleActivity );
			
			play();
		}
		
		private function createCustomTooltip ( e : ToolTipEvent ) : void
		{
			if ( !isActive ) return;
			e.toolTip = new FlexAnimatedCatTooltip();
            e.toolTip.text = ( e.target as FlexAnimatedCat ).toolTip;
		}
		
		private function positionCustomTooltip ( e : ToolTipEvent ) : void
		{
			if ( !isActive ) return;
			// on positionne le tooltip :
            // On utilise localToGlobal pour définir la position du champs (e.target) dans la zone d'affichage de l'appli
            // car le tooltip est ajouté par le TooltipManager directement sur le stage de l'application.
            // C'est important dans le cas ou le champs se trouve encapsulé dans un composant par exemple
            
            e.toolTip.x = ( ( e.target as FlexAnimatedCat ).parent as UIComponent ).contentToGlobal( new Point( e.target.x, e.target.y ) ).x - e.toolTip.width / 2 - ADJUST_X;
            e.toolTip.y = ( ( e.target as FlexAnimatedCat ).parent as UIComponent ).contentToGlobal( new Point( e.target.x, e.target.y ) ).y - e.toolTip.height - ADJUST_Y;
            
            // Note : Quand la fonction de positionnement se trouve réellement dans un autre composant on peut remplacer :
            // e.toolTip.x = ((e.target as UIComponent).parent as UIComponent).contentToGlobal(...
            // par :
            // e.toolTip.x = localToGlobal(...
		}
		
		protected function handleActivity ( e : MouseEvent ) : void
		{
			isActive = ! isActive;
			
			CursorHandler.setBusyCursor();
			ToolTipManager.enabled = isActive;
			mouseEnabled 	= false;
			buttonMode 		= false;
			
			if ( isActive )
			{
				statesRequested.push( 
						new FlexAnimatedCatStateVO( IDLE_TO_INACTIVE + UNDERSCORE + START, true )
						);
			}
			else
			{
				statesRequested.push( 
						new FlexAnimatedCatStateVO( INACTIVE_TO_IDLE + UNDERSCORE + START, true )
						);
			}
		}
		
		protected function requestHelp ( e : MouseEvent ) : void
		{
			if ( isActive )
			{
				statesRequested.push(
						new FlexAnimatedCatStateVO( ACTIVE_MEOW + UNDERSCORE + START )
						);
			}
		}
		
		protected function handleStateChange( e : Event ) : void
		{			
			if( currentFrame == totalFrames )
			{
				stop();
				Alert.show( "le script a atteint le nombre maximum de frames (erreur donc)" );
			}
			
			if( currentLabel == null )
				return;
			
			if( currentLabel.slice( -3, currentLabel.length )  == "end" )
			{
				CursorHandler.setCustomCursor();
				if ( !mouseEnabled )
					mouseEnabled 	= true;
				if ( !buttonMode )
					buttonMode		= true;
					
				readyToPlay 	= true;
				var target : FlexAnimatedCatStateVO = resolveNextTarget();
				
				if ( target == null )
					Alert.show( "le script n'a pas été capable de déterminer la prochaine cible" );
				else
				{
					attainNextTarget( target.type );
				}
			}
			else if ( currentLabel.slice( -4, currentLabel.length ) == "start" )
			{
				if ( readyToPlay )
					readyToPlay = false;
			}
		}
		
		protected function resolveNextTarget ( ) : FlexAnimatedCatStateVO
		{
			var concreteTarget 	: FlexAnimatedCatStateVO = getSomeRandomState();;
			var alternatives	: uint = statesRequested.length;
			
			if ( alternatives == 0 )
			{
				return concreteTarget;
			}
			else
			{
				for ( var i : uint = 0 ; i < alternatives ; i++ )
				{
					if ( FlexAnimatedCatStateVO( statesRequested[ i ] ).mandatory )
					{
						concreteTarget = statesRequested[ i ];
						clearStatesRequested();
						return concreteTarget;
					}
				}
				
				for ( var j : int = alternatives-1 ; j >= 0 ; j-- )
				{
					if ( FlexAnimatedCatStateVO( statesRequested[ j ] ).multiple > 0 )
					{
						concreteTarget = statesRequested[ j ];
						if ( FlexAnimatedCatStateVO( statesRequested[ j ] ).multiple >= 2 )
							clearStatesRequested( int( j ) );
						else
							clearStatesRequested();
						return concreteTarget;
					}
				}
				
			}
			return concreteTarget;
		}
		
		protected function attainNextTarget ( 
												value 			: String,
												dispatch 		: Boolean = false
												) : void
		{
			if ( ! readyToPlay )
			{
				Alert.show( "on demande la lecture alors que la lecture n'est pas autorisée" );
				return;
			}
			
			gotoAndPlay( value );
			
			if( dispatch )
			{
				// REIMPLEMENTER LE DISPATCH EVENT SI ON L'UTILISE, SINON ENLEVER
				// dispatchEvent( new AnimatedCatEvent( AnimatedCatEvent.TYPE, valeurATransporter? ) );
			}
			if ( hasEnteredSection )
				hasEnteredSection = false;
		}
		
		private function getSomeRandomState ( ) : FlexAnimatedCatStateVO
		{
			if ( isActive )
			{
				return new FlexAnimatedCatStateVO( getRandomIdleState() + UNDERSCORE + START );
				
			}
			else
			{
				return new FlexAnimatedCatStateVO( getRandomInactiveState() + UNDERSCORE + START );
			}
		}
		
		private function clearStatesRequested ( exception : int = -1) : void
		{
			if ( exception == -1 || FlexAnimatedCatStateVO( statesRequested[ 0 ] ).multiple <= 1 )
				_statesRequested = new Array();
			else
			{
				statesRequested = _statesRequested.splice( exception, 1 );
				FlexAnimatedCatStateVO( statesRequested[ 0 ] ).multiple--;
			}
		}
		
		private function resolveSectionText ( val : String ) : String
		{
			var returnText : String;
			switch( val )
			{
				case MainConf.LOGIN_VIEW:
					returnText = MainConf.LOGIN_HELP_MESSAGE;
					break;
				case MainConf.HOME_VIEW:
					returnText = MainConf.HOME_HELP_MESSAGE;
					break;
				case MainConf.MEDIA_VIEW:
					returnText = MainConf.MEDIA_HELP_MESSAGE;
					break;
				case MainConf.VISIO_VIEW:
					returnText = MainConf.VISIO_HELP_MESSAGE;
					break;
				case MainConf.CALENDAR_VIEW:
					returnText = MainConf.CALENDAR_HELP_MESSAGE;
					break;
				default:
					returnText = MainConf.LOGIN_HELP_MESSAGE;
					break;
			}
			return returnText;
		}
		
		////////////////////////////////////////////////////////////////////////////////
		// PROPRIETES DE CLASSE (GETTERS & SETTERS) //// STATES
		////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * @return isActive : if the cat is in "on" mode or in "off" mode
		 */
		public function get isActive ( ) : Boolean
		{
			return _isActive;
		}
		
		public function set isActive ( val : Boolean ) : void
		{
			_isActive = val;
		}
		
		/**
		 * @return readyToPlay : if the cat is ready to carry on with the following animation
		 */
		public function get readyToPlay ( ) : Boolean
		{
			return _readyToPlay;
		}
		
		public function set readyToPlay ( val : Boolean ) : void
		{
			_readyToPlay = val;
		}
		
		/**
		 * @return statesRequested : multiple animations requests save storage
		 */
		public function get statesRequested ( ) : Array
		{
			return _statesRequested;
		}
		
		public function set statesRequested ( val : Array ) : void
		{
			_statesRequested = ArrayUtils.arrayCopy( val );
		}
		
		/**
		 * @return currentSection : the current visited section
		 */
		public function get currentSection ( ) : String
		{
			return _currentSection;
		}
		
		public function set currentSection ( val : String ) : void
		{
			if ( _currentSection != val )
			{
				_currentSection = val;
				toolTip = resolveSectionText( val );
				hasEnteredSection = true;
			}
		}
		
		public function get hasEnteredSection ( ) : Boolean
		{
			return _hasEnteredSection;
		}
		
		public function set hasEnteredSection ( val : Boolean ) : void
		{
			_hasEnteredSection = val;
			if ( val )
			{
				statesRequested.push(
						new FlexAnimatedCatStateVO( ACTIVE_MEOW + UNDERSCORE + START, false, 5 )
						);
			}
		}
		
		////////////////////////////////////////////////////////////////////////////////
		// METHODES UTILITAIRES DE LA CLASSE
		////////////////////////////////////////////////////////////////////////////////
		
		public function getFrameNumber( frame : * ) : uint
		{
			if ( frame is uint || frame is int )
			{
				var frameNum	: uint		= uint( frame );
				if ( frameNum )
					return frameNum;
			}
			else if ( frame is String )
			{
				var label		: String	= String( frame );
				if ( label == null )
					return 0;
				frameNum = labels[label];
					return frameNum;
			}
			return 0;			
		}
		
		private function mapLabels():void
		{
			var lbls	: Array = currentLabels;
			labels = {};
			for ( var i : uint = 0; i < lbls.length; i++ )
			{
				labels[ lbls[ i ].name ] = lbls[ i ].frame;
			}
		}
		
		private function getRandomIdleState ( ) : String
		{
			var j : Number = Math.round( ( Math.random() * 4 ) );
			switch ( j )
			{
				case 1:
					return IDLE_INITIAL;
					break;
				case 2:
					return IDLE_HEADSHAKE;
					break;
				case 3:
					return IDLE_TAILSHAKE;
					break;
				case 4:
					return IDLE_PAWSHAKE;
					break;
				default:
					return IDLE_INITIAL;
					break;
			}
		}
		
		private function getRandomInactiveState ( ) : String
		{
			var j : Number = Math.round( ( Math.random() * 3 ) );
			switch ( j )
			{
				case 1:
					return INACTIVE_SLEEP;
					break;
				case 2:
					return INACTIVE_DROWSE;
					break;
				case 3:
					return INACTIVE_YAWN;
					break;
				default:
					return INACTIVE_SLEEP;
					break;
			}
		}
	}
}